from datetime import datetime
import json
from itertools import groupby

import requests
from django.contrib.auth import get_user_model, hashers, login, authenticate
from django.db import transaction
from django.db.models import Prefetch, Max
from django.conf import settings
from django.utils.http import urlquote
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView, Response, status
from rest_framework import viewsets, mixins
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.views import TokenViewBase
from rest_framework.decorators import action
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend

from .models import Role, Permission, AccountRoles, RolePermissions, Account
from .filters import AccountFilter, RoleFilter, TeacherFilter
from .serializers import RoleListSerializer, PermsListSerializer, AccountSerializer, RoleCreateSerializer, \
    AccountUpdateSerializer, CustomTokenRefreshSerializer, TeacherSerializer
from utils.common import Pagination
from ..school.models import Classes, Faculty

User = get_user_model()


def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)

    return {
        'token': str(refresh.access_token),
    }


# 测试用
class LoginView(APIView):

    def post(self, request):
        username = request.data.get('username', '')
        password = request.data.get('password', '')
        try:
            user = Account.objects.get(username=username)

            response_data = get_tokens_for_user(user)
            user.last_login = datetime.now()
            user.save()

        except Account.DoesNotExist:
            return Response({'message': '账号错误'}, status=status.HTTP_400_BAD_REQUEST)

        return Response({'data': response_data}, status=status.HTTP_200_OK)


class UserInfoView(APIView):
    """
    get:
        获取用户信息
    """
    permission_classes = [IsAuthenticated, ]

    def get(self, request):
        """
        返回用户的信息
        权限列表，roles: ['perm1','perm2',...]
        """
        user = request.user
        perms_set = user.get_all_perms(add_role_codename=True)
        perms = list(perms_set) if perms_set else ['nothing']
        res_data = {'name': user.realname, 'roles': perms}
        return Response({'data': res_data}, status=status.HTTP_200_OK)


class AccountViewSet(mixins.ListModelMixin,
                     mixins.CreateModelMixin,
                     mixins.UpdateModelMixin,
                     mixins.DestroyModelMixin,
                     viewsets.GenericViewSet):
    queryset = User.objects.all()
    pagination_class = Pagination
    serializer_class = AccountSerializer
    # permission_classes = [IsAuthenticated]
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
    filter_class = AccountFilter
    ordering_fields = ('id',)

    @action(methods=['patch'], detail=False, url_path='reset_self_password')
    def reset_self_password(self, request, pk=None):
        """ 修改个人的密码 """
        old_password = request.data.get('old_password', None)
        new_password = request.data.get('new_password', None)
        if not old_password or not new_password:
            return Response({'message': '错误：需要新密码和旧密码'}, status=status.HTTP_400_BAD_REQUEST)
        user = request.user
        if not user.check_password(old_password):
            return Response({'message': '旧密码错误，请输入正确的旧密码'}, status=status.HTTP_400_BAD_REQUEST)
        user.set_password(new_password)
        user.save()
        return Response({'message': '修改密码成功'}, status=status.HTTP_200_OK)

    @action(methods=['patch'], detail=True, url_path='reset_user_password')
    def reset_user_password(self, request, pk=None):
        """
            修改用户的密码
        :pk: 用户id, 需要
        :new_password: 新密码，需要
        """
        new_password = request.data.get('new_password', None)
        user = User.objects.filter(id=pk).first()
        if not user:
            return Response({'message': '错误：需要正确的id'}, status=status.HTTP_400_BAD_REQUEST)
        user.set_password(new_password)
        user.save()
        return Response({'message': '重置密码成功'}, status=status.HTTP_200_OK)

    def get_queryset(self):
        if self.action == 'list':
            return User.objects.prefetch_related(
                Prefetch('roles', queryset=Role.objects.only('id', 'name', 'display'))
            )
        return self.queryset

    def create(self, request, *args, **kwargs):
        roles = request.data.get('roles', None)  # 角色的id列表
        serializer = AccountSerializer(data=request.data,
                                       context={'request_user_is_superuser': request.user.is_superuser})
        serializer.is_valid(raise_exception=True)
        account_obj = serializer.save()  # 保存用户信息
        account_id = account_obj.id
        account_roles = []
        if roles is not None:
            for role_id in roles:
                account_roles.append(AccountRoles(role_id=role_id, account_id=account_id))
        if account_roles:
            AccountRoles.objects.bulk_create(account_roles, ignore_conflicts=True)
        headers = self.get_success_headers(serializer.data)
        res_data = serializer.data
        return Response(res_data, status=status.HTTP_201_CREATED, headers=headers)

    def update(self, request, *args, **kwargs):
        roles = request.data.get('roles', None)
        instance = self.get_object()

        try:
            roles_set = set(roles)
        except TypeError:
            return Response({'message': '需要正确的角色参数'}, status=status.HTTP_400_BAD_REQUEST)

        user_role_qs = AccountRoles.objects.filter(account_id=instance.id).values_list('role_id', flat=True)
        user_role_ids_set = set([role_id for role_id in user_role_qs])
        will_add = roles_set - user_role_ids_set  # 新增的角色
        will_delete = user_role_ids_set - roles_set  # 要删除的角色
        will_create_objs = [AccountRoles(account_id=instance.id, role_id=role_id) for role_id in will_add]
        will_delete_objs = AccountRoles.objects.filter(account_id=instance.id, role_id__in=will_delete)
        try:
            with transaction.atomic():
                serializer = AccountUpdateSerializer(instance, data=request.data, partial=True,
                                                     context={'request_user_is_superuser': request.user.is_superuser})
                serializer.is_valid(raise_exception=True)
                serializer.save()
                will_delete_objs.delete()
                AccountRoles.objects.bulk_create(will_create_objs)
        except Exception as e:
            return Response({'message': f'更新失败, 原因: {e.args}'}, status=status.HTTP_400_BAD_REQUEST)

        res_data = serializer.data
        return Response(res_data)


class RoleViewSet(mixins.ListModelMixin,
                  mixins.UpdateModelMixin,
                  viewsets.GenericViewSet):
    serializer_class = RoleListSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = Pagination
    queryset = Role.objects.prefetch_related('permissions').all()
    filter_backends = (DjangoFilterBackend,)
    filter_class = RoleFilter

    @action(methods=['post'], detail=True, url_path='set_role_person')
    def set_role_person(self, request, pk=None):
        """ 批量设置某个角色的成员 """
        if not (request.user.is_admin() or request.user.has_perm('role_manage')):
            return Response({'message': '您没有权限设置该角色的成员。'}, status=status.HTTP_403_FORBIDDEN)

        person_lst = request.data.get('person', [])
        person_set = set(person_lst)
        instance = Role.objects.filter(id=pk).values('name').first()
        if not instance:
            return Response({'message': '错误的id'}, status=status.HTTP_400_BAD_REQUEST)

        # 找出该角色全部成员id
        role_person_ids = AccountRoles.objects.filter(role_id=pk).values_list('account_id', flat=True)
        role_person_ids_set = set([i for i in role_person_ids])
        will_add = person_set - role_person_ids_set  # 新增的用户
        will_delete = role_person_ids_set - person_set  # 要删除的用户
        will_create_objs = [AccountRoles(account_id=account_id, role_id=pk) for account_id in will_add]
        will_delete_objs = AccountRoles.objects.filter(account_id__in=will_delete, role_id=pk)
        try:
            with transaction.atomic():
                will_delete_objs.delete()
                AccountRoles.objects.bulk_create(will_create_objs)
        except Exception as e:
            return Response({'message': f'设置成员失败, 原因: {e.args}'}, status=status.HTTP_400_BAD_REQUEST)

        # Log.objects.create(username=request.user.username, name=request.user.realname, operate_type=2,
        #                    table_name='AccountRole', comment=f'修改了角色 {instance["name"]} 的成员',
        #                    detail=str(request.data) if request.data else '')

        return Response({'message': 'ok'})

    def update(self, request, *args, **kwargs):
        if not (request.user.is_admin() or request.user.has_perm('role_manage')):
            return Response({'message': '您没有权限设置该角色的成员。'}, status=status.HTTP_403_FORBIDDEN)
        role = self.get_object()
        perms = request.data.get('permissions', None)
        if perms is None:
            return Response({'message': '缺少参数。'}, status=status.HTTP_403_FORBIDDEN)
        serializer = RoleCreateSerializer(role, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)

        if not perms:
            # 权限数组为空则是删除该角色的所有权限
            role_perms = role.permissions.all()
            role_perms_ids = [perm.id for perm in role_perms]
            RolePermissions.objects.filter(role=role, permission_id__in=role_perms_ids).delete()
            serializer.save()
        else:
            role_id = role.id
            perms_set = set(perms)
            role_perms = role.permissions.all()
            role_perms_set = set([perm.id for perm in role_perms])
            will_add = perms_set - role_perms_set
            will_delete = role_perms_set - perms_set

            objs = [RolePermissions(role_id=role_id, permission_id=perm_id) for perm_id in will_add]

            with transaction.atomic():
                save_id = transaction.savepoint()
                try:
                    serializer.save()
                    RolePermissions.objects.filter(role_id=role_id, permission_id__in=will_delete).delete()
                    RolePermissions.objects.bulk_create(objs)
                except Exception as e:
                    print(e)
                    transaction.savepoint_rollback(save_id)
                    return Response({'message': '更新角色失败'}, status=status.HTTP_400_BAD_REQUEST)
                transaction.savepoint_commit(save_id)

        res_data = serializer.data
        res_data['permissions'] = perms
        return Response(res_data)


class PermissionViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet):
    """
    list:
        以树结构显示所有权限
    """
    queryset = Permission.objects.all()
    permission_classes = [IsAuthenticated]
    serializer_class = PermsListSerializer

    def list(self, request, *args, **kwargs):
        """ 重写list方法, 以树结构返回所有权限 """
        queryset = Permission.objects.all().order_by('sort_num')
        system_name = request.query_params.get('system_name', None)
        if system_name:
            queryset = queryset.filter(system_name=system_name)
        serializer = self.get_serializer(queryset, many=True)
        perms_list = serializer.data

        # 利用list的可变对象属性，实现树形结构

        perms_dict = {}
        for perm in perms_list:
            perms_dict[perm['id']] = perm
            perms_dict[perm['id']]['child'] = []

        response_data = []
        for perm in perms_list:
            parent = perm['parent']
            if parent:
                perms_dict[parent]['child'].append(perm)
            else:
                response_data.append(perm)  # 只返回一级目录的数据

        return Response(response_data)


class MyTokenRefreshView(TokenViewBase):
    """
    自定义刷新token refresh: 刷新token的元素
    """
    serializer_class = CustomTokenRefreshSerializer



